<?php
/**
 * 洋葱供应商SDK
 * @author hujian
 */

namespace App\Service\VendorClient\ShoponionApi;

use App\Service\Code\Normal;
use App\Service\BaseService;
use Service\AppService\IdService;
use App\Service\TaskServer\TaskWorker;
use App\Model\PssModel\ServiceConfig;
use App\Model\PssModel\ShoponionArea;

class ShopOnionApiClient extends BaseService {

    //递归最多请求的次数
    const RESQ_LIMIT_TIMES = 5;

    //供应商编号
    const SUPPLIER_CODE = 'shoponion';

    //配置文件
    private $config = [];
    //发起请求的次数
    protected $resq_times = 1;

    public function __construct($apiBody = []) {
        $this->config = $apiBody;
    }

    /**
     * 创建订单
     * @param array $params
     * @return mixed
     */
    public function createOrder($param = []) {
        $orderInfo = $param['supplierOrder'];
        $goodsList = $param['orderGoods'];
        $order     = $param['order'];
        $binfo     = $param['binfo'];
        $order_sn  = $orderInfo['supplier_dsn'];
        //支付流水号
        $pay_sn = $order['paySerial'] ?? $orderInfo['pay_sn'];
        //订单时间
        $order_time = $orderInfo['cd'] ? date('Y-m-d H:i:s', $orderInfo['cd']) : date('Y-m-d H:i:s', time());
        //支付时间
        $pay_time = isset($order['payTime']) && !empty($order['payTime']) ? date('Y-m-d H:i:s', $order['payTime']) : date('Y-m-d H:i:s', time());
        //运费分摊
        $deliver_money = $orderInfo['deliver_money'];
        //下单支付的时候支付信息
        $apply_extends = @json_decode($orderInfo['apply_extends'], true);

        //判断支付方式是否存在
        $payCommanyCode = $apply_extends['payCommanyCode'] ?? '';
        $payCommanyCode = $order['payCommanyCode'] ?? $payCommanyCode;
        $payWayInfo     = ServiceConfig::instance()->getConfigByEventsValue(self::SUPPLIER_CODE, ServiceConfig::TYPE_PAY, $payCommanyCode, false);
        if (empty($payWayInfo)) {
            return Normal::returnCode(Normal::FAIL, "支付公司编码：【{$payCommanyCode}】未映射，请联系管理员处理");
        }
        //2023-08-30 17:00洋葱取消获取省市区code 直接传省市区名称
        // $areaArr      = [
        //     'province' => $orderInfo['province'],
        //     'city'     => $orderInfo['city'],
        //     'district' => $orderInfo['district'],
        // ];
        // $areaCodeInfo = ShoponionArea::instance()->getAreaCode($areaArr);
        // if ($areaCodeInfo['code'] != Normal::SUC) {
        //     return Normal::returnCode(Normal::FAIL, $areaCodeInfo['msg']);
        // }

        //获取下单商品信息
        $palceOrderGoods = [];
        $totalGoodsMoney = '0.00';
        $goodsTotalMoney = '0.00';
        foreach ($goodsList as $key => $item) {
            $tax_rate         = bcadd('1', (string)$item['tax_rate'], 4);
            $price            = $item['price'];
            $spec_num         = $item['spec_num'];
            $quantity         = $item['quantity'];
            $supplier_skucode = $item['supplier_skucode'];
            $goods_type       = $item['goods_type'];
            //实际购买数量(下单数量 X 起售数量)
            $buyAcount = $spec_num * $quantity;
            if ($key == 0) {
                $singleDeliveryMoney = bcdiv((string)$deliver_money, (string)$quantity, 3);
                $singleDeliveryMoney = bcmul((string)$singleDeliveryMoney, (string)100, 1);
                $singleDeliveryMoney = bcdiv((string)ceil($singleDeliveryMoney), (string)100, 2);
                $price               = bcadd((string)$price, (string)$singleDeliveryMoney, 2);
            }

            //不含税价格
            $singleGoodsPrice = bcdiv((string)$price, (string)$tax_rate, 3);
            $singleGoodsPrice = bcmul((string)$singleGoodsPrice, (string)100, 1);
            $singleGoodsPrice = bcdiv((string)ceil($singleGoodsPrice), (string)100, 2);
            //商品不含税总价
            $goodsTotalPrice = bcmul((string)$singleGoodsPrice, (string)$quantity, 2);
            //含税总价
            $goodsTotalPriceTax = bcmul((string)$price, (string)$quantity, 2);
            //税费
            $tax    = bcsub((string)$price, (string)$singleGoodsPrice, 2);
            $taxAll = bcmul((string)$tax, (string)$quantity, 2);
            
            //单个商品价格
            $singlePrice   = bcdiv((string)$price, (string)$spec_num,3);
            $singlePrice   = ceil(bcmul((string)$singlePrice,(string)'100',1));
            $singlePrice   = bcdiv((string)$singlePrice,'100',2);
            $totalGoods         = bcmul((string)$singlePrice,(string)$buyAcount,2);
            
            //判断是不是保税订单
            $taxAll = $goods_type == 1 ? $taxAll : 0;
            //不含税总金额
            // $goodsTotalMoney = bcadd((string)$goodsTotalMoney, (string)$goodsTotalPrice, 2);
            //含税总金额
            $goodsTotalMoney = bcadd((string)$goodsTotalMoney, (string)$totalGoods, 2);
            //下单商品组
            $goodsInfo         = [
                'unitPrice'   => (string)$singlePrice,//单价（包含了商品税金）（元）
                'buyNum'      => (int)$buyAcount,//购买量
                'discountFee' => '0.00',//商品优惠金额（元）
                'tax'         => $tax,//单个商品税金（元）；海淘商品注意：例如A商品的含税价为55.00，商品税金为4.59，则海关申报价为55.00-4.59=50.41
                'itemNo'      => $item['batch_no'],//商品货号
            ];
            $palceOrderGoods[] = $goodsInfo;
        }
        $couponFee    = $goodsTotalMoney > $orderInfo['real_total_money'] ? bcsub($goodsTotalMoney, $orderInfo['real_total_money'], 2) : '0.00';
        $requestParam = [
            'sourceOrderNo' => $order_sn,//来源订单号，唯一性不可重复
            'realName'      => $orderInfo['receive_name'],//订单的收件人真实姓名
            'cardNo'        => $orderInfo['buyer_idcard'],//订购人证件号
            'buyerName'     => $orderInfo['buyer_realname'],//订单订购人姓名
            'buyerMobile'   => $orderInfo['buyer_phone'],//订单订购人电话
            'cardType'      => 0,//卡类型（0：身份证，1：不校验卡号cardNo）
            'currency'      => 'RMB',//卡类型（0：身份证，1：不校验卡号cardNo）
            'address'       => $orderInfo['receive_address'],//收件地址，例如(黄埔大道中羊城创意园xxx)
            // 'provinceCode'  => $areaCodeInfo['data']['provinceCode'],//省份，例如广东省 或者440000，洋桃平台只支持编码。如果是国外地址对应国家编码(CN,JP,MY）
            // 'cityCode'      => $areaCodeInfo['data']['cityCode'],//城市，例如广州市 或者440100，洋桃平台只支持编码。如果国外地址对应州名。
            // 'districtCode'  => $areaCodeInfo['data']['districtCode'],//区县，例如天河区 或者440106，洋桃平台只支持编码。如果是国外地址，对应城市名。
            'provinceCode'  => $orderInfo['province'],//省份，
            'cityCode'      => $orderInfo['city'],//城市，。
            'districtCode'  => $orderInfo['district'],//区县，。
            'phone'         => $orderInfo['recveive_phone'],//收件人手机号码
            'account'       => $this->config['account'],//会员账号（客户自已的平台会员账号）
            'name'          => $this->config['name'],//会员名称（客户自已的平台会员名称）
            // 'saleFee'       => $totalGoodsMoney,//商品销售价格（元）(所有商品金额的总和)saleFee = (unitPrice - discountFee) * buyNum
            'saleFee'       => $goodsTotalMoney,//商品销售价格（元）(所有商品金额的总和)saleFee = (unitPrice - discountFee) * buyNum
            'realFee'       => $orderInfo['real_total_money'],//商品实付价格（元）(订单实付价格)realFee = saleFee + freight
            'couponFee'     => $couponFee,//优惠券金额
            'freight'       => '0.00',//运费（元）
            'commitTime'    => $order_time,//订单提交时间，格式：yyyy-MM-dd HH:mm:ss
            'paymentInfo'   => [
                'paymentCode' => $payWayInfo['service_third_value'],//订单的支付方式
                'payTime'     => $pay_time,//订单支付时间格式：yyyy-MM-dd HH:mm:ss
                'payTradeNo'  => $order['paySerial'] ?? $apply_extends['paySerial'],//在线支付交易流水号
                'paidFee'     => $orderInfo['real_total_money'],//整笔订单的实付金额（元）
                'payAccount'  => $payWayInfo['service_name'],//在线支付交易账号
                'account'     => $this->config['account'],//会员账号（客户自已的平台会员账号）
            ],//支付信息（下单合并支付）
            'orderItems'    => $palceOrderGoods,//商品明细
        ];
        $data         = [
            'method' => 'createOrder',
            'data'   => $requestParam,
        ];
        $res          = $this->execute($data);
        if ($res['code'] == Normal::SUC) {
            if (isset($res['data']['data']['orderInfo'])) {
                $subInfo = reset($res['data']['data']['orderInfo']['orderSubsInfo']);
                return Normal::returnCode(Normal::SUC, "订单推送成功", [
                    'thirdpart_order_sn' => $subInfo['subOrderNo']
                ]);
            }
            //推送成功后 调用  ’来源单号订单查询接口‘  查询其拆单号 保存至 thirdpart_order_sn 字段 查询物流要用
            $queryRes = $this->queryOrder(['supplier_dsn' => $order_sn]);
            if ($queryRes['code'] == Normal::SUC) {
                $this->resq_times = 1;
                return Normal::returnCode(Normal::SUC, "订单推送成功", [
                    'thirdpart_order_sn' => $queryRes['data']['subOrderNo']
                ]);
            }
            return $queryRes;
        }
        return $res;
    }

    /**
     * 取消订单
     * @param $data
     * @return array|string
     */
    public function cancelOrder($params = []) {
        $requestParam = [
            'account' => $this->config['account'],
            'orderNo' => $params['supplierOrder']['supplier_dsn'],
        ];
        $data         = [
            'method' => 'cancelOrder',
            'data'   => $requestParam,
        ];
        return $this->execute($data);
    }

    /**
     * 订单售后
     * @param $data
     * @return array|string
     */
    public function orderAfterSale($params = []) {
        $orderInfo = $params['supplierOrder'];
        $goodsList = $params['orderGoods'];
        $order_sn  = $orderInfo['supplier_dsn'];
        //运费分摊
        $deliver_money = $orderInfo['deliver_money'];
        //获取下单商品信息
        $palceOrderGoods = [];
        $totalGoodsMoney = '0.00';
        foreach ($goodsList as $key => $item) {
            //卖价
            $price = $item['price'];
            //商品购买规格数量
            $spec_num = $item['spec_num'];//1
            //商品购买数量
            $quantity = $item['quantity'];//2
            //实际购买数量(下单数量 X 起售数量)
            $buyAcount = $spec_num * $quantity;//2
            //商品税率
            $tax      = $item['tax_rate'];//0.0910
            $tax_rate = bcadd((string)$tax, '1.0000', 4);//1.0910
            //商品+税费
            $shipping_fee        = $key == 0 ? $deliver_money : 0;//10
            $single_shipping_fee = bcdiv((string)$shipping_fee, (string)$quantity, 3);//5
            //单个商品税费
            $single_shipping_fee = ceil((float)$single_shipping_fee * 100) / 100;//5
            //商品包邮单价（单件(含规格)）
            $price = bcadd((string)$price, (string)$single_shipping_fee, 2);//56.80
            //包邮价格(总价)
            $goodsMoney = bcmul((string)$price, (string)$quantity, 2);
            //获取商品不含税价格 ,小数第三位收了之后再进行合计计算
            $goods_price = bcdiv((string)$goodsMoney, (string)$buyAcount, 3);
            //实际商品包邮单价（单个）
            $singleGoodsPrice = ceil((float)$goods_price * 100) / 100;
            //总商品金额
            $totalGoodsMoney = bcadd($totalGoodsMoney, $goodsMoney, 2);
            //下单商品组
            $goodsInfo         = [
                'refundNum'   => (int)$buyAcount,//退款数量
                'refundTotal' => $goodsMoney,//商品总退款金额
                'itemNo'      => trim($item['batch_no']),//商品SKU货号
            ];
            $palceOrderGoods[] = $goodsInfo;
        }
        $requestParam = [
            'outRefundNo'            => $order_sn,
            'sourceOrderNo'          => $order_sn,
            'subOrderNo'             => $orderInfo['thirdpart_order_sn'],//拆单号保存到这个字段里面的
            'timeDiff'               => 1,//申请售后订单支付时间与申请时间的时间差:（0：小于六个小时，1：大于六个小时）除了Cosyfans平台都为1
            'applyTime'              => isset($orderInfo['after_sale_time']) ? date('Y-m-d H:i:s', $orderInfo['after_sale_time']) : date('Y-m-d H:i:s'),
            'refundFreight'          => '0.00',//订单退款邮费，例如20.00
            'refundItemFee'          => $totalGoodsMoney,//订单商品退款总金额(大于等于退款商品退款金额之和)，例如100.00（不包括退款邮费）
            'currency'               => 'RMB',
            // 'afterSaleReason'        => $params['order']['exceptReason'] ?? '不想要了',
            'afterSaleApplyItemList' => $palceOrderGoods
        ];
        $data         = [
            'method' => 'afterSale',
            'data'   => $requestParam,
        ];
        $res          = $this->execute($data);
        if ($res['code'] == Normal::SUC) {
            if (isset($res['data']['data']['refundNo'])) {
                return Normal::returnCode(Normal::FAIL, "申请售后失败", [
                    'isAfterSaleAsyncOrderSn' => $res['data']['data']['refundNo']
                ]);
            }
            return Normal::returnCode(Normal::FAIL, '申请售后失败');
        }
        return $res;
    }

    /**
     * 订单查询
     * @param $data
     * @return array
     */
    public function queryOrder($param = []) {
        $requestParam = [
            'account'       => $this->config['account'],
            'sourceOrderNo' => $param['supplier_dsn'],
        ];
        $data         = [
            'method' => 'queryOrder',
            'data'   => $requestParam,
        ];
        $res          = $this->execute($data);
        if (($res['code'] != Normal::SUC || !isset($res['data']['data']['orderInfo'])) && $this->resq_times <= self::RESQ_LIMIT_TIMES) {
            $this->resq_times++;
            // sleep(1);
            //0.5秒
            usleep(500000);
            return $this->queryOrder($param);
        }
        if ($res['code'] == Normal::SUC) {
            $subInfo = reset($res['data']['data']['orderInfo']['orderSubsInfo']);
            $result  = ['subOrderNo' => $subInfo['subOrderNo']];
            return Normal::returnCode(Normal::SUC, "获取拆单信息成功", $result);
        }
        return Normal::returnCode(Normal::FAIL, '获取拆单信息失败');
    }

    /**
     * 商品列表
     */
    public function queryGoodsList($param = []) {
        $requestParam = [
            'method' => 'queryGoods',
            'data'   => [
                'pageNum'    => $param['page'] ?? 1,
                'pageSize'   => $param['limit'] ?? 50,
                'itemType'   => 99,
                'updateTime' => null,
                'language'   => 'cn'
            ]
        ];
        $response     = $this->execute($requestParam);
        if ($response['code'] == Normal::SUC && !empty($response['data']['data'])) {
            $newData = [];
            $stockIds = [];
            foreach ($response['data']['data'] as $item) {
                foreach ($item['skuList'] as $sku) {
                    $item['skuList']   = [];
                    $item['skuList'][] = $sku;
                    $newData[]         = $item;
                    $stockIds[]        = $sku['skuId'];
                }
            }
            $response['data']['data'] = $newData;
            //批量获取批次
            $stockMaps = $this->batchQueryStock($stockIds);
            if (!empty($stockMaps)){
                foreach ($response['data']['data'] as &$datum){
                    $skuInfo = reset($datum['skuList']);
                    if ($skuInfo && isset($stockMaps[$skuInfo['skuId']])){
                        $datum['skuList'][0]['availableStock'] = $stockMaps[$skuInfo['skuId']];
                    }
                }
            }
        }
        return $response;
    }

    /**
     * 批量查询库存
     * @param $param
     * @return array
     */
    public function batchQueryStock($stockIds = [])
    {
        if (empty($stockIds)){
            return [];
        }
        $requestParam = [
            'method' => 'queryStock',
            'data'   => [
                'itemIds'    => implode(',',$stockIds),
            ]
        ];
        $response = $this->execute($requestParam);
        if ($response['code'] != Normal::SUC){
           return [];
        }
        return $response['data']['data'];
    }

    /**
     * 签名
     * @param $data
     * @return string
     */
    public function sign($data) {
        ksort($data);
        $arrTmp = [];
        foreach ($data as $k => $v) {
            //参数为空不参与签名
            if (isset($v) && $v !== '') {
                if (is_array($v)) {
                    $v = json_encode($v, 320);
                }
                array_push($arrTmp, "$k=$v");
            }
        }
        $stringA = implode('&', $arrTmp);
        $stringB = $stringA . "&key=" . $this->config['app_secret'];
        $stringC = md5($stringB);
        return strtoupper($stringC);
    }

    /**
     * CURL请求
     * @param $params
     * @return mixed
     */
    public function execute($param = []) {
        if (!isset($this->config[$param['method']])) {
            return Normal::returnCode(Normal::FAIL, "请求路由未设置");
        }
        if (empty($param['data'])) {
            return Normal::returnCode(Normal::FAIL, "数据不能为空");
        }
        $url = $this->config['baseurl'] . $this->config[$param['method']];
        if (empty($url)) {
            return Normal::returnCode(Normal::FAIL, "接口地址不能为空");
        }
        $commonData        = [
            'platformId'    => $this->config['platform_id'],
            'apiv'          => $this->config['api_version'],
            'timestamp'     => date('YmdHis'),
            'userId'        => $this->config['user_id'],
            'appId'         => $this->config['app_id'],
            // "appSecret"     => $this->config['app_secret'],
            'appKey'        => $this->config['app_key'],
            'devPlatformId' => (int)$this->config['dev_platform_id'],
            'security'      => $this->config['security'],
        ];
        $pushData          = array_merge($param['data'], $commonData);
        $pushData['token'] = $this->sign($pushData);
        $parameter         = [
            [
                'tag'    => self::SUPPLIER_CODE . '_' . $param['method'],
                'uid'    => IdService::instance()->getOtherID(),
                'url'    => $url,
                'data'   => $pushData,
                'method' => 'post',
                'format' => 'json',
                'header' => [
                    "Content-Type: application/json"
                ],
            ],
        ];
        if (in_array($param['method'], ['queryGoods','queryStock'])) {
            $resTask = TaskWorker::instance()->addTask($parameter, 'handleDiableTask');
        } else {
            $resTask = TaskWorker::instance()->addTask($parameter);
        }
        $resTask = current($resTask);
        $result  = @json_decode($resTask['response']['result'], true);
        if (isset($result['status']) && $result['status'] == Normal::SUC) {
            return Normal::returnCode(Normal::SUC, "操作成功", $result);
        } else {
            $msg = $result['msg'] ?? '请求失败';
            return Normal::returnCode(Normal::FAIL, $msg);
        }
    }

    /**
     * 订单物流
     * @param $data
     * @return array|string
     */
    public function queryOrderExpress($params = []) {
        $requestParam = [
            'subOrderNo' => $params['thirdpart_order_sn']
        ];
        $data         = [
            'method' => 'orderExpress',
            'data'   => $requestParam,
        ];
        return $this->execute($data);
    }


    /**
     * 订单物流
     * @param $data
     * @return array|string
     */
    public function queryOrderAfterSale($params = []) {
        $requestParam = [
            'refundNo' => $params['after_sale_async_sn']
        ];
        $data         = [
            'method' => 'queryAfterSale',
            'data'   => $requestParam,
        ];
        return $this->execute($data);
    }
}
